
(normal-method ((a <string>) (b <integer>)) (+ 5 6))

;; Generics may be declared.

(define-generic add)

add					; => PROCEDURE

(define-method (add (a <string>) (b <string>)) 
  (string-append a b))

(add "Hello " "world!")			; => "Hello world!"

(define-method (add (a <symbol>) (b <symbol>))
  (symbol-append a b))

(add 'Hello_ 'world!)			; => Hello_world

;; Predicates can be used directly instead of the <type> notation.

(define-method (add (a <integer>) (b integer?))
  (+ a b))

(add 1 2)				; => 3

;; Values can be matched directly.

(define-method (add (a a:) (b b:))
  ab:)

(add a: b:)				; => ab:

;; This will descend to the <symbol> variant.

(add a: c:)				; => a:c:

(define-method (add (a <real>) (b <real>))
  (+ a b))

(add 1.3 2.7)				; => 4.0

(let ((op add)
      (begin-time (schedule-current-time)))
  (let loop ((i 0))
    (if (< i 100000)
	(begin (op i i)
	       (loop (+ i 1)))
	(inform "Elapsed time" (- (schedule-current-time) begin-time)))))

;; +           -> Elapsed time: 0.022729039192199707
;; add:rsc     -> Elapsed time: 0.3230239152908325
;; add:swindle -> Elapsed time: 1.209272027015686

(define-generic minus)

(define-method (minus (a <any>) (b <any>))
  (error "No, cannot arrange for that..."))

(define-method (minus (a <number>) (b <number>))
  (- a b))

minus					; => PROCEDURE

(minus 6 5)				; => 1

(minus "6" 5)				; => ERROR

;; Zero argument methods are allowed.

(define-method (minus) 0)

(minus)

;; It is *possible* to transform existing procedures into generics
;; with methods.

(define _+ (lambda a (apply + a)))

(define-generic +)

(define-method (+ (a <number>) (b <number>))
  (_+ a b))

(define-method (+ (a <string>) (b <string>))
  (string-append a b))

(+ 4 5)

(+ "test" "ing")
